package com.setup.trac.dao;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.transform.ResultTransformer;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.setup.trac.pojo.Tickets;

public class DAOService {

	private DAO dao;
	private int maxResults;

	/***********************************************************
	 * METODI FIND
	 ***********************************************************/
	public <T> T[] findAll(T[] t, Class<?> aClass) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		DetachedCriteria criteria = getCriteria(aClass);
		List<?> result = ht.findByCriteria(criteria);
		return result.toArray(t);

	}

	public <T> T[] findAll(T[] t, Class<?> aClass, int firstResult) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		List<?> result = createCriteriaWithRange(aClass, firstResult, ht);
		return result.toArray(t);

	}

	public <T> T[] findByExample(T[] t, Object persistentObject) {
		List<?> result = getDao().getHibernateTemplate().findByExample(
				persistentObject);
		return result.toArray(t);
	}

	public <T> T[] findByCriteria(T[] t, Criterion criterion, Class<?> aClass) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		DetachedCriteria criteria = getCriteria(aClass).add(criterion);
		List<?> result = ht.findByCriteria(criteria);
		return result.toArray(t);
	}

	public <T> T[] findByCriteria(T[] t, Criterion criterion, Class<?> aClass,
			int firstResult) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		List<?> result = createCriteriaWithRange(criterion, aClass,
				firstResult, ht);
		return result.toArray(t);
	}

	public Object count(Criterion criterion, Class<?> aClass) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		List<?> result = createCriteriaForCount(criterion, aClass, ht);
		return result.get(0);
	}

	public Object count(Class<?> aClass) {
		return count(null, aClass);
	}

	private List<?> createCriteriaWithRange(Criterion criterion,
			Class<?> aClass, int firstResult, HibernateTemplate ht) {
		Session session = ht.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(aClass);
		if (criterion != null) {
			criteria.add(criterion);
		}
		criteria.setFirstResult(firstResult);
		criteria.setMaxResults(getMaxResults());
		List<?> result = criteria.list();
		return result;
	}

	private List<?> createCriteriaWithRange(Class<?> aClass, int firstResult,
			HibernateTemplate ht) {
		return createCriteriaWithRange(null, aClass, firstResult, ht);
	}

	private List<?> createCriteriaForCount(Criterion criterion,
			Class<?> aClass, HibernateTemplate ht) {
		Session session = ht.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(aClass);
		if (criterion != null) {
			criteria.add(criterion);
		}
		criteria.setProjection(Projections.rowCount());
		List<?> result = criteria.list();
		return result;
	}

	public <T> T[] findByNamedQuery(T[] t, String queryName, Object... values) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		List<?> result = ht.findByNamedQuery(queryName, values);
		return result.toArray(t);
	}

	public <T> T[] find(T[] t, final String queryString,
			final ResultTransformer transformer, final Object... paramsValues) {
		HibernateTemplate ht = getDao().getHibernateTemplate();

		List<?> result = ht.executeFind(new HibernateCallback() {
			public List<?> doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createSQLQuery(queryString);
				if (transformer != null) {
					query.setResultTransformer(transformer);
				}
				if (paramsValues != null) {
					for (int i = 0; i < paramsValues.length; i++) {
						Object param = paramsValues[i];
						query.setParameter(i, param);
					}
				}
				List result = query.list();
				return result;
			}
		});
		return result.toArray(t);
	}

	public <T> T findByPK(Class<T> entityClass, Serializable id) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		return ht.get(entityClass, id);
	}

	/***********************************************************
	 * METODI INSERT
	 ***********************************************************/
	public Object insert(Object persistenceObj) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		Object result = ht.save(persistenceObj);
		return result;

	}

	public void delete(Object persitentObject) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		ht.delete(persitentObject);
	}

	public void update(Object persistentObj) {
		HibernateTemplate ht = getDao().getHibernateTemplate();
		ht.saveOrUpdate(persistentObj);
	}

	public DetachedCriteria getCriteria(Class class1) {
		return DetachedCriteria.forClass(class1);
	}

	public DAO getDao() {
		return dao;
	}

	public void setDao(DAO dao) {
		this.dao = dao;
	}

	public int getMaxResults() {
		return maxResults;
	}

	public void setMaxResults(int maxResults) {
		this.maxResults = maxResults;
	}

}
